#include "cEnemyManager.h"

cEnemyManager::cEnemyManager(void)
{
}

cEnemyManager::~cEnemyManager(void)
{
}

void cEnemyManager::Finalize()
{
	this->UnLoad();
}

bool cEnemyManager::Load(char* filename)
{
	cLog *Log= cLog::Instance();
	FILE *f;
	f=fopen(filename,"r");

	if(f == NULL)
	{
		printf("Cannot open %s for reading!\n", filename);
		return false;
	}

	int status = 0; // 0=start, 1=reading nodes, 2=reading connections

	char line[80];

	while(fgets(line, 80, f) != NULL)
	{
		int type;
		int x;
		int y;

		sscanf(line,"%d %d %d",&type,&x,&y);

		EnemyType eType;
		switch(type)
		{
		case 0:
			eType = TYPE_1;
			break;
		case 1:
			eType = TYPE_2;
			break;
		case 2:
			eType = TYPE_3;
			break;
		default:
			Log->Msg("Unknown enemy type!");
			break;
		}
		
		cEnemy* enemy = new cEnemy(eType,x,y);
		enemy->SetActive(false);

		this->list.push_back(enemy);
	}

	fclose(f);

	return true;

	return true;
}

void cEnemyManager::UnLoad()
{
	this->list.clear();
}

EnemyList* cEnemyManager::GetList()
{
	return &this->list;
}

void cEnemyManager::Process(cMap* Map, cGraph *Graph, cItem *Item, cPersonaje *Personaje)
{
	//
	// Process enemies AI
	//
	int nEnemies = this->list.size();

	int pX,pY;

	Personaje->GetLevelPosition(&pX,&pY);

	//
	// for each enemy
	//
	for(int i = 0; i<nEnemies; i++)
	{
		cEnemy *enemy = this->list.at(i);

		int eX,eY,next_eX,next_eY;
		int next_direction;
		
		enemy->GetLevelPosition(&eX,&eY);

		// Not activated yet (it becomes active the first time it appears on the screen)
		if(!enemy->IsActive())
		{
			//
			// If enemy is in the screen
			//
			if( (Map->GetPositionLevel() + SCREEN_WIDTH) > eX)
			{
				enemy->SetActive(true);
				enemy->SetDirection(E_STOPL);
			}
		}
		else if(enemy->GetDirection() == E_HITR || enemy->GetDirection() == E_HITL || enemy->GetDirection() == E_DIEL)
		{
			//enemy->ResetSeq();
		}
		else if(enemy->GetDirection() == E_DIER)
		{
			enemy->Death();
		}
		else if(!enemy->isDeath() && enemy->IsActive())
		{
			// Player is active already. Compute its next candidate move
			GetNextMove(enemy,Personaje,&next_eX,&next_eY,&next_direction);
			//GetNextPathMove(Graph, enemy,Personaje,&next_eX,&next_eY,&next_direction);

			int primaryCollisionSide;
			int secondaryCollisionSide;

			//
			// Ok, but before move the enemy, there is a lot of collision logic to do
			//
			bool collided = CheckCollisionWithPlayer(enemy,Personaje,&primaryCollisionSide,&secondaryCollisionSide);

			if(collided)
			{
				switch(primaryCollisionSide)
				{
				case E_COLLISION_LEFT:
					enemy->SetDirection(E_ATTACKR);
					enemy->SetLevelPosition(eX,next_eY); // do not change X

					//Decrement Health
					Personaje->SetHealth(Personaje->GetHealth()-1);
					Personaje->SetDirection(HITL);
					

					break;
				case E_COLLISION_RIGHT:
					enemy->SetDirection(E_ATTACKL);
					enemy->SetLevelPosition(eX,next_eY); // do not change X

					//Decrement Health
					Personaje->SetHealth(Personaje->GetHealth()-1);
					Personaje->SetDirection(HITR);
					

					break;
				case E_COLLISION_TOP:
					enemy->SetDirection(next_direction);
					enemy->SetLevelPosition(eX,eY); // do not change Y
					break;
				case E_COLLISION_BOTTOM:
					enemy->SetDirection(next_direction);
					enemy->SetLevelPosition(eX,eY); // do not change Y
					break;
				default:
					break;
				}
			}
			else
			{
				// Move towads the player
				// No collision with given player
				enemy->SetDirection(next_direction);
				enemy->SetLevelPosition(next_eX,next_eY);
			}
			
			//
			// Check collison with objects
			//

		} 
	}
}

//
// This should be the A* algorithm
// 
void cEnemyManager::GetNextMove(cEnemy *Enemy, cPersonaje *Player, int *next_eX, int *next_eY, int* next_direction)
{
	int pX,pY;
	int eX,eY;

	Player->GetLevelPosition(&pX,&pY);
	Enemy->GetLevelPosition(&eX,&eY);

	//
	// Enemy AI - Where is the player?
	//
	if(eX>pX)
	{
		// Player on the left
		*next_direction = E_MLEFT;

		if(eY>pY)
		{
			// Player on the top
			*next_eX=eX-0.707f*E_SPEED;
			*next_eY=eY-0.707f*E_SPEED;
		}
		else if(eY<pY)
		{
			// Player on the bottom
			*next_eX=eX-0.707f*E_SPEED;
			*next_eY=eY+0.707f*E_SPEED;
		}
		else
		{
			// Same y
			*next_eX=eX-E_SPEED;
			*next_eY=eY;
		}
	}
	else
	{
		// Player on the right
		*next_direction = E_MRIGHT;

		if(eY>pY)
		{
			// Player on the top
			*next_eX = eX+0.707f*E_SPEED;
			*next_eY = eY-0.707f*E_SPEED;
		}
		else if(eY<pY)
		{
			// Player on the bottom
			*next_eX = eX+0.707f*E_SPEED;
			*next_eY = eY+0.707f*E_SPEED;
		}
		else
		{
			// Same y
			*next_eX = eX+E_SPEED;
			*next_eY = eY;
		}
	}
}


void cEnemyManager::GetNextPathMove(cGraph *Graph, cEnemy *Enemy, cPersonaje *Player, int *next_eX, int *next_eY, int* next_direction)
{
	int pX,pY;
	int eX,eY;

	cPath* path = Enemy->GetPath();

	Player->GetLevelPosition(&pX,&pY);
	Enemy->GetLevelPosition(&eX,&eY);

	if(!path->IsDone())
	{
		int move = path->NextStep(next_eX, next_eY);

		if(move==ARRIVE)
		{
			path->Done();
		}
		else if(move==CONTINUE)
		{
		//	step++;
		}
	}
	else
	{
		float cost;
		std::vector< void* >* resultPath = new vector<void*>();

		// busca otro path
		Graph->Find(eX,eY,pX,pY,resultPath,&cost);

		path->Init(resultPath);

		Enemy->SetPath(path);
	}
}


bool cEnemyManager::CheckCollisionWithPlayer(cEnemy *Enemy, cPersonaje *Player, int *primaryCollisionSide, int *secondaryCollisionSide)
{
	int eX,eY,eW,eH;
	int pX,pY,pW,pH;
	
	RECT eRect;
	RECT pRect;
	RECT iRect;

	Enemy->GetLevelPosition(&eX,&eY);
	Enemy->GetSize(&eW,&eH);
	Player->GetLevelPosition(&pX,&pY);
	Player->GetSize(&pW,&pH);

	SetRect(&eRect,eX,eY+(3*(eH/4)),eX+E_WIDTH,eY+eH);
	SetRect(&pRect,pX,pY+(3*(pH/4)),pX+P_WIDTH,pY+pH);

	char output[4096];

	BOOL intersect = IntersectRect(&iRect,&eRect,&pRect);
	
	if(!intersect)
		return false;

	bool horizontal = (iRect.bottom - iRect.top) < (iRect.right-iRect.left);
	bool vertical = !horizontal;

	bool fromRight = (eRect.right > pRect.right);//(eRect.left < pRect.right) && (eRect.left > pRect.left) && (eRect.right > pRect.right) && (eRect.right > pRect.left);
	bool fromLeft  = (eRect.left < pRect.left);//(pRect.right > eRect.right) && (eRect.right > pRect.left) && (eRect.left < pRect.left);

	bool fromTop = (eRect.top < pRect.top);//(eRect.bottom > pRect.top) && (eRect.bottom < pRect.bottom) && (eRect.top < pRect.top);
	bool fromBottom = (eRect.bottom > pRect.bottom);//(eRect.top < pRect.bottom) && (eRect.top > pRect.top) && (eRect.bottom > pRect.bottom);

	if(vertical)
	{
		if(fromRight)
		{
			*primaryCollisionSide = E_COLLISION_RIGHT;
		}
		else
		{
			
			*primaryCollisionSide = E_COLLISION_LEFT;
		}

		if(fromTop)
		{
			*secondaryCollisionSide = E_COLLISION_TOP;
		}
		else
		{
			*secondaryCollisionSide = E_COLLISION_BOTTOM;
		}
	}
	else
	{
		if(fromTop)
		{
			*primaryCollisionSide = E_COLLISION_TOP;
		}
		else
		{
			*primaryCollisionSide = E_COLLISION_BOTTOM;
		}

		if(fromRight)
		{
			*secondaryCollisionSide = E_COLLISION_RIGHT;
		}
		else
		{
			*secondaryCollisionSide = E_COLLISION_LEFT;
		}
	}

	return true;
}
